package com.selebash.features.impl;

import com.google.gson.JsonElement;
import com.selebash.annotation.Feature;
import com.selebash.ast.AbstractAst;
import com.selebash.ast.FeatureAst;
import com.selebash.ast.JsonAst;
import com.selebash.exception.SelebashException;
import com.selebash.runtime.ExecutionContext;
import com.selebash.runtime.NestedExecutionProcessor;
import java.util.List;
import java.util.Map;

/**
 * @author sad
 */
public class DefaultSelebashFeatures {

    @Feature(value = "повторить (.*?) раз", hasNested = true)
    protected void repeat(ExecutionContext executionContext, final int times) {
        System.out.println("повторить " + times);
        executionContext.setRunNested(new NestedExecutionProcessor() {

            @Override
            public void processInnerNodes(ExecutionContext executionContext, List<AbstractAst> nodes) {
                for (int i = 0; i < times; i++) {
                    super.processInnerNodes(executionContext, nodes);
                }
            }
        });
    }
    
    @Feature(value = "обойти таблицу \\\"?(.*?)\\\"?", hasNested = true)
    protected void table(ExecutionContext executionContext, String data) {
        final JsonAst jsonAst = (JsonAst) executionContext.getMainScript().getFunctionNode(data);
        if (jsonAst == null) {
            throw new SelebashException("Не найден json массив " + data);
        }
        if (!jsonAst.getJson().isJsonArray()) {
            throw new SelebashException("Нельзя обойти json объект " + data + " так как это не json массив");
        }
        executionContext.setRunNested(new NestedExecutionProcessor() {

            @Override
            public void processInnerNodes(ExecutionContext executionContext, List<AbstractAst> nodes) {
                for (JsonElement el : jsonAst.getJson().getAsJsonArray()) {
                    if (!el.isJsonNull()) {
                        for (Map.Entry<String, JsonElement> e : el.getAsJsonObject().entrySet()) {
                            if (!e.getValue().isJsonPrimitive()) {
                                throw new SelebashException("При обходе таблицы, вложенные объекты не допускаются. Лишь примитивы - " + e.getKey() + ":" + e.getValue().toString());
                            }
                            executionContext.setVariable(e.getKey(), e.getValue().getAsJsonPrimitive().getAsString());
                        }

                        super.processInnerNodes(executionContext, nodes);
                    }
                }
            }
        });
    }

    @Feature("переменная ([^\\s]*?)\\s*=\\s*(.*)")
    protected void setVariable(ExecutionContext executionContext, String varName, String varValue) {
        executionContext.setVariable(varName, varValue);
    }

    @Feature("напечатать переменную\\s+([^\\s]*?)")
    protected void printvar(ExecutionContext executionContext, String varName, FeatureAst astNode) {
        String value = executionContext.getVariableAsString(varName);
        System.out.print(value);
    }

    @Feature("напечатать новую строку")
    protected void printnewline() {
        System.out.println();
    }

    @Feature(value = "И", hasNested = true)
    protected void and(ExecutionContext executionContext) {
    }

    @Feature(value = "Или", hasNested = true)
    protected void or(ExecutionContext executionContext) {
        executionContext.setRunNested(new NestedExecutionProcessor() {
            private int successfullCount = 0;

            @Override
            public boolean afterStep(Exception ex, ExecutionContext executionContext) {
                if (ex == null) {
                    successfullCount++;
                    return false;
                }

                return true;
            }

            @Override
            public boolean afterExecution(ExecutionContext executionContext) {
                return successfullCount != 0;
            }
        });
    }

    @Feature("Ошибка (.*)")
    protected void error(String error) {
        throw new SelebashException(error);
    }
}
